package com.zbkj.admin.service.impl;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.googlecode.aviator.AviatorEvaluator;
import com.googlecode.aviator.Expression;
import com.zbkj.admin.service.AdminEstimateAiHandleService;
import com.zbkj.admin.service.AdminProjectHandleV2Service;
import com.zbkj.common.config.BaseConfig;
import com.zbkj.common.constants.CityWeightConfConstants;
import com.zbkj.common.constants.Constants;
import com.zbkj.common.enums.*;
import com.zbkj.common.exception.CommonException;
import com.zbkj.common.function.ListsumFunction;
import com.zbkj.common.model.project.*;
import com.zbkj.common.model.standard.PeFormula;
import com.zbkj.common.model.standard.PeProjectStandard;
import com.zbkj.common.model.system.SystemAdmin;
import com.zbkj.common.model.user.User;
import com.zbkj.common.model.user.UserBill;
import com.zbkj.common.oss.OssClientUtil;
import com.zbkj.common.page.CommonPage;
import com.zbkj.common.request.enquiry.ReportRequest;
import com.zbkj.common.request.project.*;
import com.zbkj.common.response.UploadResponse;
import com.zbkj.common.response.project.*;
import com.zbkj.common.response.standard.ReportDetailResponse;
import com.zbkj.common.utils.CommonUtil;
import com.zbkj.common.utils.FileUtil;
import com.zbkj.common.vo.MyRecord;
import com.zbkj.common.vo.project.*;
import com.zbkj.common.vo.user.UserDatavalVo;
import com.zbkj.service.service.UploadService;
import com.zbkj.service.service.project.*;
import com.zbkj.service.service.standard.IPeFormulaService;
import com.zbkj.service.service.standard.IPeProjectStandardService;
import com.zbkj.service.service.standard.IPeStandardResultService;
import com.zbkj.service.service.user.UserBillService;
import com.zbkj.service.service.user.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Auther:
 * @Date: 2024/9/13 08:56
 * @Description:
 */
@Slf4j
@Service
public class AdminProjectHandleV2ServiceImpl implements AdminProjectHandleV2Service {

    @Autowired
    private BaseConfig baseConfig;
    @Autowired
    @Lazy
    private AdminProjectHandleV2Service adminProjectHandleV2Service;
    @Autowired
    private ProjectInfoService projectInfoService;
    @Autowired
    private ProjectInformationService projectInformationService;
    @Autowired
    private OssClientUtil ossClientUtil;
    @Autowired
    private EstimateAiService estimateAiService;
    @Autowired
    private UploadService uploadService;
    @Autowired
    @Lazy
    private AdminEstimateAiHandleService adminEstimateAiHandleService;
    @Autowired
    private EstimateInformationService estimateInformationService;
    @Autowired
    private ReportApplyAuditService reportApplyAuditService;
    @Autowired
    private EstimateFunService estimateFunService;
    @Autowired
    private EstimateFundocService estimateFundocService;
    @Autowired
    private AireqTaskService aireqTaskService;
    @Autowired
    private CityWeightService cityWeightService;
    @Autowired
    private ProjectParamGuoService projectParamGuoService;
    @Autowired
    private ProjectParamJunService projectParamJunService;
    @Autowired
    private UserBillService userBillService;
    @Autowired
    private UserService userService;
    @Autowired
    private IPeAiWriteHistoryService peAiWriteHistoryService;

    @Autowired
    private IPeStandardResultService peStandardResultService;

    @Autowired
    private IPeProjectStandardService peProjectStandardService;

    @Autowired
    private IPeFormulaService peFormulaService;




    @Override
    public PageInfo<AdminProjectInfoResponse> projectList(AdminProjectQueryRequest queryRequest) {
        ProjectQueryVo queryVo = new ProjectQueryVo();
        if(Objects.nonNull(queryRequest.getQueryStatus())) {
            queryVo.setStatusList(Lists.newArrayList(queryRequest.getQueryStatus()));
        }
        queryVo.setKeyword(queryRequest.getProjectName());
        queryVo.setStatusSort(queryRequest.getQueryStatus());
        queryVo.setSourceType(0);
        queryVo.setSource(0);
        queryVo.setBeginDate(queryRequest.getBeginDate());
        queryVo.setEndDate(queryRequest.getEndDate());
        //分页查询项目列表
        PageInfo<ProjectInfo> projectPage = projectInfoService.projectList(queryVo,queryRequest.getPage(),queryRequest.getLimit());
        List<AdminProjectInfoResponse> responseList = Lists.newArrayList();
        for(ProjectInfo projectInfo : projectPage.getList()) {
            AdminProjectInfoResponse response = new AdminProjectInfoResponse();
            BeanUtils.copyProperties(projectInfo, response);
            responseList.add(response);
        }
        return CommonPage.copyPageInfo(projectPage, responseList);
    }

    @Override
    public AdminProjectInfoResponse getProjectInfo(Long projectId) {
        ProjectInfo projectInfo = this.getProjectAndCheck(projectId);
        AdminProjectInfoResponse response = new AdminProjectInfoResponse();
        BeanUtils.copyProperties(projectInfo,response);
        //获取调整因子对象
        ProjectParamResponse projectParam = this.getProjectParam(projectInfo.getId(),projectInfo.getProjectType(),0);
        response.setProjectParam(projectParam);
        List<InformationResponse> informationResponseList = this.getValidProjectFileList(projectId);
        response.setInformationResponseList(informationResponseList);
        return response;
    }

    @Override
    public List<InformationResponse> getValidProjectFileList(Long projectId) {
        List<ProjectInformation> dbList = projectInformationService.getValidProjectInformationList(projectId);
        List<InformationResponse> responseList = Lists.newArrayList();
        for(ProjectInformation pojo : dbList) {
            InformationResponse vo = new InformationResponse();
            BeanUtils.copyProperties(pojo, vo);
            vo.setFilePath(ossClientUtil.addDomain(vo.getFilePath()));
            //vo.setCreatePhone(CommonUtil.maskMobile(vo.getCreatePhone()));
            responseList.add(vo);
        }
        return responseList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void aiContentSubmit(AdminAiContentRequest contentRequest, SystemAdmin systemAdmin) {
        ProjectInfo projectInfo = this.getProjectAndCheck(contentRequest.getProjectId());
        if(!ProjectStatusEnum.isToEstimate(projectInfo.getStatus())) {
            throw new CommonException("项目状态已变更，请刷新后重试");
        }
        List<EstimateAi> estimateAiList = Lists.newArrayList();
        //List<String> contentList = Lists.newArrayList();

        String aiReqNo = CommonUtil.getRandomStr("");
        for(AdminAiContentRequest.ContentRequest content : contentRequest.getContentList()) {
            EstimateAi eai = new EstimateAi();
            BeanUtils.copyProperties(content,eai);
            eai.setProjectId(projectInfo.getId());
            eai.setCreateId(systemAdmin.getId().longValue());
            eai.setReqNo(aiReqNo);
            estimateAiList.add(eai);
            //contentList.add(content.getContent());
        }
        if(CollectionUtils.isNotEmpty(estimateAiList)) {
            ProjectInfo updateProject = new ProjectInfo();
            updateProject.setId(projectInfo.getId());
            updateProject.setAireqNo(aiReqNo);
            updateProject.setStatus(ProjectStatusEnum.IN_ESTIMATE.getStatus());
            //updateProject.setEstimateSource(1);
            updateProject.setEstimateBeginTime(new Date());
            ProjectModifyConditionVo conditionVo = new ProjectModifyConditionVo();
            conditionVo.setStatusList(Lists.newArrayList(ProjectStatusEnum.TO_ESTIMATE.getStatus()));
            //更新项目信息
            boolean flag = projectInfoService.updateProject(updateProject,conditionVo);
            if(!flag) {
                throw new CommonException("项目已变更，请刷新后重试");
            }
            //删除原有内容记录
            estimateAiService.delByProjectId(projectInfo.getId());
            estimateAiService.saveBatch(estimateAiList,estimateAiList.size());
            estimateFunService.updateStatusToHis(projectInfo.getId());
            AiEstimateRequest aiRequest = new AiEstimateRequest();
            aiRequest.setReqNo(aiReqNo);
            adminEstimateAiHandleService.estimateAiReqParamBuild(2,aiRequest,projectInfo,estimateAiList,null);
            //调用AI系统进行估算
            adminEstimateAiHandleService.estimateStartAiRequest(aiRequest);
        } else {
            throw new CommonException("缺少内容记录");
        }
    }

    @Override
    public List<EstimateAi> aiContentList(Long projectId) {
        return estimateAiService.getAiContentList(projectId);
    }

    @Override
    public ProjectInfo getProjectAndCheck(Long projectId) {
        ProjectInfo projectInfo = projectInfoService.getById(projectId);
        if(Objects.isNull(projectInfo) || projectInfo.getDeleteFlag() != 0) {
            throw new CommonException("项目信息不存在");
        }
        /*if(ProjectStatusEnum.isWithdrawn(projectInfo.getStatus())) {
            throw new CommonException("项目已被撤回");
        }*/
        return projectInfo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void reportApplyAudit(AdminReportApplyAuditRequest auditRequest, SystemAdmin systemAdmin) {
        ProjectInfo projectInfo = this.getProjectAndCheck(auditRequest.getProjectId());
        if(!ReportApplyStatusEnum.isInStatus(projectInfo.getReportApplyStatus())) {
            throw new CommonException("报告申请状态已变更");
        }
        ProjectInfo updateProject = new ProjectInfo();
        updateProject.setId(projectInfo.getId());
        ProjectModifyConditionVo conditionVo = new ProjectModifyConditionVo();
        conditionVo.setStatusList(Lists.newArrayList(ProjectStatusEnum.COMPLET_ESTIMATE.getStatus()));
        conditionVo.setReportApplyStatusList(Lists.newArrayList(ReportApplyStatusEnum.IN_APPLY.getStatus()));
        ReportApplyAudit reportApplyAudit = null;
        if(ReportApplyStatusEnum.isRejectStatus(auditRequest.getStatus())) {
            //申请驳回处理
            if(StringUtils.isBlank(auditRequest.getRejectReason())) {
                throw new CommonException("请填写驳回原因");
            }
            updateProject.setReportApplyStatus(ReportApplyStatusEnum.REJECT_APPLY.getStatus());
            //驳回审记录
            reportApplyAudit = new ReportApplyAudit();
            reportApplyAudit.setProjectId(auditRequest.getProjectId());
            reportApplyAudit.setRejectReason(auditRequest.getRejectReason());
            reportApplyAudit.setCreateId(systemAdmin.getId().longValue());
        } else if(ReportApplyStatusEnum.isPassStatus(auditRequest.getStatus())) {
            //申请通过处理
            updateProject.setReportApplyStatus(ReportApplyStatusEnum.PASS_APPLY.getStatus());
            updateProject.setReportStartTime(new Date());
            updateProject.setStatus(ProjectStatusEnum.IN_REPORT.getStatus());
        } else {
            throw new CommonException("审核状态参数错误");
        }
        //更新项目信息
        boolean flag = projectInfoService.updateProject(updateProject,conditionVo);
        if(!flag) {
            throw new CommonException("项目已变更，请刷新后重试");
        }
        if(Objects.nonNull(reportApplyAudit)) {
            //保存驳回原因记录
            reportApplyAuditService.save(reportApplyAudit);
        }
    }

    @Override
    public void reportNotifClient(Long projectId) {
        ProjectInfo projectInfo = this.getProjectAndCheck(projectId);
        if(!ProjectStatusEnum.isInReport(projectInfo.getStatus())) {
            throw new CommonException("项目状态已变更，请刷新后重试");
        }
        if(projectInfo.getReportFlag().intValue() == 0) {
            throw new CommonException("项目报告未上传,不能进行报告通知操作");
        }
        ProjectInfo updateProject = new ProjectInfo();
        updateProject.setId(projectInfo.getId());
        updateProject.setReportFlag(2);
        //更新条件对象
        ProjectModifyConditionVo conditionVo = new ProjectModifyConditionVo();
        //设置更新检查条件
        conditionVo.setStatusList(Lists.newArrayList(ProjectStatusEnum.IN_REPORT.getStatus()));
        boolean updateFlag = projectInfoService.updateProject(updateProject, conditionVo);
    }

    @Override
    public UploadResponse informationUpload(Integer type, MultipartFile multipartFile) {
        if(!InformationTypEnum.typeCheck(type,InformationTypEnum.TYPE43.getType())) {
            throw new CommonException("文件类型参数错误");
        }
        if(multipartFile == null || multipartFile.isEmpty()) {
            throw new CommonException("上传文件不能为空");
        }
        UploadResponse uploadResponse = new UploadResponse();
        uploadResponse.setFileName(multipartFile.getOriginalFilename());
        String fileType = FilenameUtils.getExtension(uploadResponse.getFileName());
        if(!CommonUtil.fileTypeCheck(Constants.ADMIN_FILE_TYPES,fileType)) {
            throw new CommonException("上传文件类型错误");
        }
        uploadResponse.setExtName(fileType);
        uploadResponse.setFileSize(multipartFile.getSize());
        String fileUrl =  uploadService.informationUpload(fileType, multipartFile);
        uploadResponse.setUrl(fileUrl);
        return uploadResponse;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void estimateFileSave(AdminInfomationRequest infomationRequest, SystemAdmin systemAdmin) {
        Long projectId = infomationRequest.getProjectId();
        ProjectInfo projectInfo = this.getProjectAndCheck(projectId);
        Integer requestFileType = infomationRequest.getFileType();
        if(InformationTypEnum.typeCheck(requestFileType, InformationTypEnum.TYPE43.getType())){
            ProjectInfo updateProject = new ProjectInfo();
            updateProject.setId(projectInfo.getId());
            updateProject.setReportTime(new Date());
            if(projectInfo.getReportFlag().intValue() == 0) {
                updateProject.setReportFlag(1);
            }
            ProjectModifyConditionVo conditionVo = new ProjectModifyConditionVo();
            conditionVo.setStatusList(Lists.newArrayList(ProjectStatusEnum.IN_REPORT.getStatus()));
            //更新项目信息
            boolean flag = projectInfoService.updateProject(updateProject,conditionVo);
            if(!flag) {
                throw new CommonException("项目已变更，请刷新后重试");
            }
        } else {
            throw new CommonException("资料类型参数错误");
        }
        //保存上传文件记录
        estimateInformationService.informationSaveProcess(infomationRequest,systemAdmin.getId().longValue());
    }

    @Override
    public InformationResponse getValidEstimateFile(Long projectId, Integer type) {
        EstimateInformation information = estimateInformationService.getOneRecord(null, projectId, type, CommonStatusEnum.VALID_STATUS.getStatus());
        InformationResponse response = new InformationResponse();
        if(Objects.isNull(information)) {
            throw new CommonException("项目资料还未生成，请稍后再试");
        }
        BeanUtils.copyProperties(information,response);
        response.setFilePath(ossClientUtil.addDomain(response.getFilePath()));
        return response;
    }

    @Override
    public EstimateRestProjectResponse getEstimateResult(Long projectId) {
        ProjectInfo projectInfo = this.getProjectAndCheck(projectId);
        EstimateRestProjectResponse restResponse = new EstimateRestProjectResponse();
        BeanUtils.copyProperties(projectInfo,restResponse);
        restResponse.setProjectId(projectInfo.getId());
        //军标项目信息配置重用程度选项对应系数
        restResponse.setReuseVal(ProjectFunItem1Enum.findItemVal(projectInfo.getProjectType(),projectInfo.getReuseItem()));
        //人月费用
        restResponse.setPerMonthFee(cityWeightService.getPerMonthFee(projectInfo.getProjectType(),projectInfo.getCityCode()));
        //获取调整因子对象
        ProjectParamResponse projectParam = this.getProjectParam(projectInfo.getId(),projectInfo.getProjectType(),2);
        restResponse.setProjectParam(projectParam);
        List<EstimateFun> estimateFunList = estimateFunService.getValidFunDetailList(projectInfo.getId(),3, projectInfo.getAireqNo());
        List<EstimateFunDetailResponse> restFunList = Lists.newArrayList();
        for(EstimateFun fun : estimateFunList) {
            EstimateFunDetailResponse temFunResp = new EstimateFunDetailResponse();
            BeanUtils.copyProperties(fun,temFunResp);
            restFunList.add(temFunResp);
        }
        /*if(CollectionUtils.isEmpty(restFunList)) {
            restResponse.setSoftwareFun(null);
            restResponse.setSoftwareFee(null);
        }*/
        restResponse.setFunDetailList(restFunList);
        return restResponse;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public EstimateFunEditRestResponse estimateFunSave(AdminEstimateFunSaveRequest saveRequest,SystemAdmin systemAdmin) {
        ProjectInfo projectInfo = this.getProjectAndCheck(saveRequest.getProjectId());
        if(!Objects.equals(projectInfo.getAireqNo(),saveRequest.getAireqNo())) {
            throw new CommonException("功能点明细信息已变更，请刷新后重试");
        }
        //入参检查
        this.estimateFunSaveParamCheck(saveRequest, projectInfo.getProjectType());
        //新增明细 vo to pojo
        List<EstimateFun> saveFunDetailList =  AdminEstimateFunDetailSaveRequest.voToPojoBatch(0,projectInfo.getProjectType(),systemAdmin.getId().longValue(),saveRequest,saveRequest.getNewFunList());
        //编辑明细 vo to pojo
        List<EstimateFun> updateFunDetailList = AdminEstimateFunDetailSaveRequest.voToPojoBatch(1,projectInfo.getProjectType(),systemAdmin.getId().longValue(),saveRequest,saveRequest.getModifyFunList());
        //批量保存新增功能明细
        estimateFunService.saveEstimateFunList(saveFunDetailList);
        //批量更新功能明细
        estimateFunService.updateEstimateFunList(updateFunDetailList);
        //批量删除功能明细
        estimateFunService.modifyStatusDel(projectInfo.getId(),saveRequest.getDelIdList());
        //将已生成的编辑后功能点明细文件置为失效
        estimateInformationService.updateStatusToHis(saveRequest.getProjectId(),Lists.newArrayList(InformationTypEnum.TYPE42.getType()));
        //重新进行估算计算
        SoftwareCalcVo calcVo = this.estimateReusltCalc(projectInfo.getId(),projectInfo.getProjectType(),projectInfo.getCityCode());
        ProjectInfo updateProject = new ProjectInfo();
        updateProject.setId(projectInfo.getId());
        updateProject.setSoftwarePoints(calcVo.getSoftwarePoints());
        updateProject.setSoftwareFun(calcVo.getSoftwareFun());
        updateProject.setSoftwareFee(calcVo.getSoftwareFee());
        ProjectModifyConditionVo conditionVo = new ProjectModifyConditionVo();
        conditionVo.setNeStatusList(Lists.newArrayList(ProjectStatusEnum.TO_ESTIMATE.getStatus()));
        conditionVo.setAireqNo(projectInfo.getAireqNo());
        //更新项目信息
        boolean flag = projectInfoService.updateProject(updateProject,conditionVo);
        if(!flag) {
            throw new CommonException("项目已变更，请刷新后重试");
        }
        EstimateFunEditRestResponse funEditRestResponse = new EstimateFunEditRestResponse();
        //组装返回对象
        funEditRestResponse.setProjectId(projectInfo.getId());
        //重新进行估算计算后赋值
        funEditRestResponse.setSoftwarePoints(calcVo.getSoftwarePoints());
        funEditRestResponse.setSoftwareFun(calcVo.getSoftwareFun());
        funEditRestResponse.setSoftwareFee(calcVo.getSoftwareFee());
        return funEditRestResponse;
    }

    @Override
    public InformationResponse getEstimateFunFile(Long projectId,SystemAdmin systemAdmin) {
        ProjectInfo projectInfo = this.getProjectAndCheck(projectId);
        String aireqNo = projectInfo.getAireqNo();
        EstimateInformation information = estimateInformationService.getValidFileObject(projectId, InformationTypEnum.TYPE42.getType(),aireqNo);
        InformationResponse response = new InformationResponse();
        if(Objects.nonNull(information)) {
            BeanUtils.copyProperties(information,response);
            response.setFilePath(ossClientUtil.addDomain(response.getFilePath()));
            return response;
        }
        //获取编辑后的功能点明细list
        List<EstimateFun> estimateFunList = estimateFunService.getValidFunDetailList(projectInfo.getId(),null, projectInfo.getAireqNo());
        if(CollectionUtils.isEmpty(estimateFunList)) {
            throw new CommonException("功能点明细还未生成，请稍后再试");
        }
        //生成功能点明细文件并上传OSS
        EstimateInformation saveInfomation = this.estimateFunToExcelAndToOss(estimateFunList,projectId,aireqNo,systemAdmin.getId().longValue());
        estimateInformationService.save(saveInfomation);
        BeanUtils.copyProperties(saveInfomation,response);
        response.setFilePath(ossClientUtil.addDomain(response.getFilePath()));
        return response;
    }

    private EstimateInformation estimateFunToExcelAndToOss(List<EstimateFun> estimateFunList, Long productId, String reqNo, Long adminUid) {
        List<EstimateFunToExcelVo> funToExcelVoList = Lists.newArrayList();
        for (EstimateFun estimateFun : estimateFunList) {
            EstimateFunToExcelVo funToExcelVo = new EstimateFunToExcelVo();
            BeanUtils.copyProperties(estimateFun,funToExcelVo);
            //重用程度-选项名称
            funToExcelVo.setItme1Str(ProjectFunItem1Enum.getItemName(estimateFun.getItme1()));
            //修改类型-选项名称
            funToExcelVo.setItme2Str(ProjectFunItem2Enum.getItemName(estimateFun.getItme2()));
            String stateStr = EstimateFunModifyStateEnum.getStateStrFomMap(EstimateFunModifyStateEnum.getStateStrMap(),estimateFun.getModifyState());
            funToExcelVo.setModifyStateStr(stateStr);
            funToExcelVoList.add(funToExcelVo);
        }
        String tempFilePath = baseConfig.getLocalTempFilePath(Constants.PROJECT_DOC_PREFIX,".xlsx");
        File localFile = new File(tempFilePath);
        FileUtil.dirCreate(localFile.getParentFile());
        try {
            EasyExcel.write(localFile, EstimateFunToExcelVo.class)
                    .sheet()
                    .doWrite(() -> {return funToExcelVoList;});
            String ossFileName = String.format("功能点_%s",localFile.getName());
            String fileUrl = uploadService.informatLocalUpload(localFile,ossFileName);
            EstimateInformation information = new EstimateInformation();
            information.setProjectId(productId);
            information.setReqNo(reqNo);
            information.setFileType(InformationTypEnum.TYPE42.getType());
            information.setFileName(ossFileName);
            information.setFilePath(ossClientUtil.clearDomain(fileUrl));
            information.setStatus(0);
            information.setCreateId(adminUid);
            return information;
        } catch (CommonException ce) {
            log.error("功能点编辑文件下载-projectId:{}-reqNo:{}-生成异常:",productId,reqNo,ce);
            throw ce;
        } catch (Exception e) {
            log.error("功能点编辑文件下载-projectId:{}-reqNo:{}-生成异常:",productId,reqNo,e);
            throw new CommonException("生成功能点明细文件失败");
        } finally {
            if(localFile.exists() && localFile.isFile()) {
                localFile.delete();
            }
        }
    }

    @Override
    public void statusConfirm(Long projectId, Integer status) {
        ProjectInfo projectInfo = this.getProjectAndCheck(projectId);
        ProjectInfo updateProject = new ProjectInfo();
        updateProject.setId(projectInfo.getId());
        //更新条件对象
        ProjectModifyConditionVo conditionVo = new ProjectModifyConditionVo();
        if(ProjectStatusEnum.isCompletEstimate(status)) { //复审完成项目状态 估算中->估算完成
            if(!ProjectStatusEnum.isInEstimate(projectInfo.getStatus())) {
                throw new CommonException("项目不为估算中状态，不能进行复审完成操作");
            }
            updateProject.setStatus(status);
            updateProject.setEstimateFlag(1);
            updateProject.setEstimateConfirmTime(new Date());
            //设置更新检查条件
            conditionVo.setStatusList(Lists.newArrayList(ProjectStatusEnum.IN_ESTIMATE.getStatus()));
        } else if(ProjectStatusEnum.isFinish(status)) { //报告完成项目状态 报告中->报告完成
            if(!ProjectStatusEnum.isInReport(projectInfo.getStatus()) && projectInfo.getReportFlag().intValue() == 0) {
                throw new CommonException("项目报告未上传,不能进行报告完成操作");
            }
            updateProject.setStatus(status);
            updateProject.setCompleteTime(new Date());
            updateProject.setReportFlag(2);
            //设置更新检查条件
            conditionVo.setStatusList(Lists.newArrayList(ProjectStatusEnum.IN_REPORT.getStatus()));
        } else {
            throw new CommonException("操作状态参数错误");
        }
        boolean updateFlag = projectInfoService.updateProject(updateProject, conditionVo);
        if(!updateFlag) {
            throw new CommonException("项目信息已变更，请稍后再试");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int aiAutomCallTask(AireqTask task) {
        ProjectInfo projectInfo = projectInfoService.getById(task.getProjectId());
        if(Objects.isNull(projectInfo) || projectInfo.getDeleteFlag() != 0) {
            log.info("自动ai估算任务-taskId:{}-productId:{}-项目已删除，取消请求任务",task.getId(),task.getProjectId());
            return 2;
        }
        if(!task.getReqNo().equals(projectInfo.getAireqNo())) {
            log.info("自动ai估算任务-taskId:{}-productId:{}-ai请求流水号已重置,取消请求任务",task.getId(),task.getProjectId());
            return 2;
        }
        ProjectInfo updateProject = new ProjectInfo();
        updateProject.setId(projectInfo.getId());
        updateProject.setStatus(ProjectStatusEnum.FINISH.getStatus());
        updateProject.setEstimateBeginTime(new Date());
        ProjectModifyConditionVo conditionVo = new ProjectModifyConditionVo();
        conditionVo.setStatusList(Lists.newArrayList(ProjectStatusEnum.TO_ESTIMATE.getStatus()));
        conditionVo.setAireqNo(task.getReqNo());
        //更新项目信息
        boolean flag = projectInfoService.updateProject(updateProject,conditionVo);
        if(!flag) {
            log.info("自动ai估算任务-taskId:{}-productId:{}-项目更新失败",task.getId(),task.getProjectId());
            return 2;
        }
        aireqTaskService.updateTaskStatus(task.getId(), 1, " ");
        AiEstimateRequest aiRequest = new AiEstimateRequest();
        aiRequest.setReqNo(task.getReqNo());
        List<ProjectInformation>  informationList = projectInformationService.getValidProjectInformationList(projectInfo.getId());
        adminEstimateAiHandleService.estimateAiReqParamBuild(1,aiRequest,projectInfo,null,informationList);
        //调用AI系统进行估算
        adminEstimateAiHandleService.estimateStartAiRequest(aiRequest);
        return 1;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void aiNotifyResultSaveHandle(AiNotifyRequest notifyRequest, ProjectInfo projectInfo, List<AiNotifyFunExcelParseVo> parseFunDataList) {
        ProjectInfo updateProject = new ProjectInfo();
        updateProject.setId(projectInfo.getId());
        updateProject.setEstimateEndTime(new Date());
        updateProject.setAiNotfiyFlag(1);
        ProjectModifyConditionVo conditionVo = new ProjectModifyConditionVo();
        conditionVo.setStatusList(Lists.newArrayList(ProjectStatusEnum.IN_ESTIMATE.getStatus()));
        conditionVo.setAireqNo(notifyRequest.getReqNo());
        //更新项目信息
        boolean flag = projectInfoService.updateProject(updateProject,conditionVo);
        EstimateInformation information = new EstimateInformation();
        information.setProjectId(projectInfo.getId());
        information.setFileType(InformationTypEnum.TYPE41.getType());
        information.setFileName(FilenameUtils.getName(notifyRequest.getFilePath()));
        information.setFilePath(notifyRequest.getFilePath());
        information.setReqNo(notifyRequest.getReqNo());
        information.setAifunPoints(notifyRequest.getTotalAns());
        if(!flag) {
            //项目更新失败--只记录ai估算结果文件（非生效状态）
            information.setStatus(1);
            estimateInformationService.save(information);
        } else {
            //将当前有效估算文件置为历史,保存当前ai估算结果
            estimateInformationService.updateStatusToHis(notifyRequest.getProjectId(), Lists.newArrayList(InformationTypEnum.TYPE41.getType(),InformationTypEnum.TYPE42.getType()));
            information.setStatus(0);
            estimateInformationService.save(information);
            //保存解析出的功能点明细数据
            List<EstimateFun> efList =  AiNotifyFunExcelParseVo.toPojoBatch(projectInfo,notifyRequest.getReqNo(),parseFunDataList);
            //将已有的功能点明细置为历史状态
            estimateFunService.updateStatusToHis(projectInfo.getId());
            if(CollectionUtils.isNotEmpty(efList)) {
                estimateFunService.saveBatch(efList);
            }
            //索引文档信息
            List<EstimateFundoc> docList = FunDocVo.toPojoBatch(projectInfo.getId(),notifyRequest.getReqNo(),notifyRequest.getSrcTextList());
            //将当前索引文档置为历史后批量进行增加
            estimateFundocService.updateSatusToHis(projectInfo.getId());
            if(CollectionUtils.isNotEmpty(docList)) {
                estimateFundocService.saveBatch(docList);
            }
            //计算估算软件规模和软件评估费用 并更新项目估算自动
            SoftwareCalcVo softwareCalcVo = this.estimateReusltCalc(projectInfo.getId(),projectInfo.getProjectType(),projectInfo.getCityCode());
            ProjectInfo upp = new ProjectInfo();
            upp.setId(projectInfo.getId());
            upp.setSoftwarePoints(softwareCalcVo.getSoftwarePoints());
            upp.setSoftwareFun(softwareCalcVo.getSoftwareFun());
            upp.setSoftwareFee(softwareCalcVo.getSoftwareFee());
            //根据ai返回功能点数计算评估费用
            BigDecimal aiFunPoints = Objects.isNull(notifyRequest.getTotalAns()) ? null : new BigDecimal(notifyRequest.getTotalAns());
            SoftwareCalcVo aiCalcVo = this.estimateCalcHandle(0,projectInfo.getId(),projectInfo.getProjectType(),projectInfo.getCityCode(), aiFunPoints);
            upp.setAisoftwarePoints(aiCalcVo.getSoftwarePoints());
            upp.setAisoftwareFun(aiCalcVo.getSoftwareFun());
            upp.setAisoftwareFee(aiCalcVo.getSoftwareFee());
            ProjectModifyConditionVo pmc = new ProjectModifyConditionVo();
            pmc.setAireqNo(notifyRequest.getReqNo());
            projectInfoService.updateProject(upp,pmc);
        }
    }
    @Override
    public SoftwareCalcVo estimateReusltCalc(long projectId, int projectType, String cityCode) {
        //估算软件规模
        BigDecimal softwarePoints = estimateFunService.sumFunPointsByProjectId(projectId);
        //计算软件规模和评估费用
        return this.estimateCalcHandle(2,projectId,projectType,cityCode,softwarePoints);
    }

    /**
     * 计算软件规模和评估费用
     * @param queryType 0 只查询客户端维护参数 不存在返回null
     *                  1 只查询服务端维护参数 不存在返回 null
     *                  2 优先查服务端维护参数 不存在查询客户端维护参数 都不存在返回null
     * @param projectId
     * @param projectType
     * @param cityCode
     * @param funPoints
     * @return
     */
    private SoftwareCalcVo estimateCalcHandle(int queryType, long projectId, int projectType, String cityCode, BigDecimal funPoints) {
        SoftwareCalcVo calcVo = new SoftwareCalcVo();
        if(Objects.isNull(funPoints)) {
            return calcVo;
        }
        calcVo.setSoftwarePoints(funPoints);
        //软件评估费用
        if(projectType == 1) { //国标计算
            ProjectParamGuo paramGuo = projectParamGuoService.getParamGouByQueryType(queryType,projectId);
            calcVo.setSoftwareFun(CityWeightConfConstants.softwareFun1Calc(funPoints,paramGuo));
            BigDecimal cityVal = cityWeightService.getWeightVal(cityCode);
            calcVo.setSoftwareFee(CityWeightConfConstants.softwareFee1Calc(calcVo.getSoftwareFun(),cityVal));
        } else if(projectType == 2) { //军标计算
            ProjectParamJun paramJun = projectParamJunService.getParamJunByQueryType(queryType,projectId);
            calcVo.setSoftwareFun(CityWeightConfConstants.softwareFun2Calc(funPoints,paramJun));
            calcVo.setSoftwareFee(CityWeightConfConstants.softwareFee2Calc(calcVo.getSoftwareFun()));
        }
        return calcVo;
    }


    @Override
    public void demoProjectAutoHandleTask(Long projectId) {
        ProjectInfo projectInfo = this.getProjectAndCheck(projectId);
        if(!ProjectStatusEnum.isToEstimate(projectInfo.getStatus())) {
            throw new CommonException("项目不为待估算状态");
        }
        List<ProjectInformation> informationList = projectInformationService.getValidProjectInformationList(projectId);
        ProjectInfo updateProject = new ProjectInfo();
        updateProject.setId(projectInfo.getId());
        updateProject.setStatus(ProjectStatusEnum.FINISH.getStatus());
        updateProject.setEstimateFlag(1);
        updateProject.setEstimateBeginTime(new Date());
        updateProject.setAiNotfiyFlag(1);
        updateProject.setEstimateEndTime(new Date());
        updateProject.setEstimateConfirmTime(new Date());
        updateProject.setReportApplyStatus(3);
        updateProject.setReportStartTime(new Date());
        updateProject.setReportFlag(2);
        updateProject.setReportTime(new Date());
        updateProject.setCompleteTime(new Date());
        updateProject.setAireqNo(CommonUtil.getRandomStr(""));
        String estimateFilePath = "";
        String reportFilePath = "";
        for(ProjectInformation information : informationList) {
            if("快递管家PC端.docx".equals(information.getFileName())) {
                updateProject.setSoftwareFun(new BigDecimal("274"));
                updateProject.setSoftwareFee(new BigDecimal("357300"));
                estimateFilePath = "20240924/快递管家PC端功能点明细.xlsx";
                reportFilePath = "20240924/快递管家PC端价格预估咨询报告.pdf";
                break;
            } else if("临床思维综合训练系统软件需求分析.docx".equals(information.getFileName())) {
                estimateFilePath = "20240924/临床思维综合训练系统软件功能点明细.xlsx";
                reportFilePath = "20240924/临床思维综合训练系统软件价格预估咨询报告.pdf";
                updateProject.setSoftwareFun(new BigDecimal("904"));
                updateProject.setSoftwareFee(new BigDecimal("1178700"));
                break;
            }
        }
        if(StringUtils.isBlank(estimateFilePath)) {
            throw new CommonException("估算文件为空");
        }
        //项目估算集合
        List<EstimateInformation>  estFileInfoList = Lists.newArrayList();
        //ai通知估算结果文件
        EstimateInformation estimateFile = new EstimateInformation();
        estimateFile.setProjectId(updateProject.getId());
        estimateFile.setFileType(InformationTypEnum.TYPE41.getType());
        estimateFile.setFileName(FilenameUtils.getName(estimateFilePath));
        estimateFile.setFilePath(ossClientUtil.clearDomain(estimateFilePath));
        estimateFile.setStatus(0);
        estimateFile.setReqNo(updateProject.getAireqNo());
        estFileInfoList.add(estimateFile);

        //报告文件
        EstimateInformation report = new EstimateInformation();
        report.setProjectId(updateProject.getId());
        report.setFileType(InformationTypEnum.TYPE43.getType());
        report.setFileName(FilenameUtils.getName(reportFilePath));
        report.setFilePath(ossClientUtil.clearDomain(reportFilePath));
        report.setStatus(0);
        estFileInfoList.add(report);

        AiNotifyRequest notifyParam = new AiNotifyRequest();
        notifyParam.setProjectId(updateProject.getId());
        notifyParam.setReqNo(updateProject.getAireqNo());
        notifyParam.setFilePath(estimateFilePath);
        //解析估算结果文件
        List<AiNotifyFunExcelParseVo> funParseVoList = adminEstimateAiHandleService.aiNotifyFileParse(notifyParam);
        int idx = 0;
        List<EstimateFun> efList = Lists.newArrayList();
        for(AiNotifyFunExcelParseVo parseVo : funParseVoList) {
            EstimateFun estimateFun = new EstimateFun();
            BeanUtils.copyProperties(parseVo,estimateFun);
            estimateFun.setProjectId(updateProject.getId());
            estimateFun.setReqNo(updateProject.getAireqNo());
            idx += 1;
            estimateFun.setSortNum(idx);
            efList.add(estimateFun);
        }
        //演示项目-自动处理保存
        adminProjectHandleV2Service.demoProjectAutoHandleSave(updateProject, estFileInfoList, efList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void demoProjectAutoHandleSave(ProjectInfo projectInfo, List<EstimateInformation> estFileInfoList, List<EstimateFun> efList) {
        ProjectModifyConditionVo conditionVo = new ProjectModifyConditionVo();
        conditionVo.setStatusList(Lists.newArrayList(ProjectStatusEnum.TO_ESTIMATE.getStatus()));
        //更新项目信息
        boolean flag = projectInfoService.updateProject(projectInfo,conditionVo);
        if(!flag) {
            throw new CommonException("项目信息更新失败");
        }
        //保存ai估算通知结果文件及报告文件
        if(CollectionUtils.isNotEmpty(estFileInfoList)) {
            estimateInformationService.delByProjectId(projectInfo.getId(),null);
            estimateInformationService.saveBatch(estFileInfoList);
        }
        //保存功能点明细
        if(CollectionUtils.isNotEmpty(efList)) {
            estimateFunService.delByProjectId(projectInfo.getId());
            estimateFunService.saveBatch(efList);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void projectParamEditSave(ProjectParamSaveRequest paramSaveRequest) {
        ProjectInfo projectInfo = this.getProjectAndCheck(paramSaveRequest.getProjectId());
        if(projectInfo.getProjectType() == 1) {
            ProjectParamGuo paramGuo = ProjectParamGuoRequest.paramGuoCheckAndToPojo(paramSaveRequest.getParamGuoRequest());
            projectParamGuoService.paramSaveFromAdmin(projectInfo.getId(),paramGuo);
        } else {
            ProjectParamJun paramJun = ProjectParamJunRequest.paramJunCheckAndToPojo(paramSaveRequest.getParamJunRequest());
            projectParamJunService.paramSaveFromAdmin(projectInfo.getId(),paramJun);
        }
        //重新进行估算计算--重新处理
        SoftwareCalcVo calcVo = this.estimateReusltCalc(projectInfo.getId(),projectInfo.getProjectType(),projectInfo.getCityCode());
        ProjectInfo updateProject = new ProjectInfo();
        updateProject.setId(projectInfo.getId());
        updateProject.setSoftwarePoints(calcVo.getSoftwarePoints());
        updateProject.setSoftwareFun(calcVo.getSoftwareFun());
        updateProject.setSoftwareFee(calcVo.getSoftwareFee());
        ProjectModifyConditionVo conditionVo = new ProjectModifyConditionVo();
        conditionVo.setNeStatusList(Lists.newArrayList(ProjectStatusEnum.TO_ESTIMATE.getStatus()));
        //更新项目信息
        boolean flag = projectInfoService.updateProject(updateProject,conditionVo);
        if(!flag) {
            throw new CommonException("项目已变更，请刷新后重试");
        }
    }

    @Override
    public List<EstimateFunDocResponse> getEstimateFunDoc(Long projectId) {
        ProjectInfo projectInfo = this.getProjectAndCheck(projectId);
        Map<Integer,Integer> idxCountMap =  estimateFunService.findIdxCount(projectId);
        List<EstimateFundoc> fundocList = estimateFundocService.getFundocList(projectInfo.getId(),projectInfo.getAireqNo());
        List<EstimateFunDocResponse> responseList = Lists.newArrayList();
        for(EstimateFundoc fundoc : fundocList) {
            EstimateFunDocResponse response = new EstimateFunDocResponse();
            BeanUtils.copyProperties(fundoc,response);
            response.setFunCount(idxCountMap.getOrDefault(response.getIdx(),0));
            responseList.add(response);
        }
        return responseList;
    }

    @Override
    public void estimateFunToAi(Long projectId) {
        ProjectInfo projectInfo = this.getProjectAndCheck(projectId);
        if(ProjectStatusEnum.isToEstimate(projectInfo.getStatus())) {
            throw new CommonException("项目为待估算状态，无法操作");
        }
        List<EstimateFun> estimateFunList = estimateFunService.getValidFunDetailList(projectInfo.getId(),3, projectInfo.getAireqNo());
        if(CollectionUtils.isEmpty(estimateFunList)) {
            throw new CommonException("估算功能明细还未生成，请稍后重试");
        }
        EstimateFunToAiRequest aiRequest = new EstimateFunToAiRequest();
        aiRequest.setProjectId(projectInfo.getId());
        aiRequest.setProjectName(projectInfo.getProjectName());
        aiRequest.setProjectType(projectInfo.getProjectType());
        aiRequest.setFunDetailList(Lists.newArrayList());
        aiRequest.setSrcTextList(Lists.newArrayList());
        for(EstimateFun fun : estimateFunList) {
            AiNotifyFunExcelParseVo funVo = new AiNotifyFunExcelParseVo();
            BeanUtils.copyProperties(fun,funVo);
            aiRequest.getFunDetailList().add(funVo);
        }
        //获取索引文档结合
        List<EstimateFundoc> fundocList = estimateFundocService.getFundocList(projectInfo.getId(),projectInfo.getAireqNo());
        for (EstimateFundoc fundoc : fundocList) {
            FunDocVo docVo = new FunDocVo();
            BeanUtils.copyProperties(fundoc,docVo);
            aiRequest.getSrcTextList().add(docVo);
        }
        //调用AI系统进行估算
        adminEstimateAiHandleService.estimateFunToAiCall(aiRequest);

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void projectFefundHandle(ProjectInfo projectInfo) {
        ProjectInfo updateProject = new ProjectInfo();
        updateProject.setId(projectInfo.getId());
        updateProject.setStatus(ProjectStatusEnum.WITHDRAWN.getStatus());
        ProjectModifyConditionVo conditionVo = new ProjectModifyConditionVo();
        conditionVo.setStatusList(Lists.newArrayList(ProjectStatusEnum.IN_ESTIMATE.getStatus()));
        conditionVo.setAireqNo(projectInfo.getAireqNo());
        //更新项目信息
        boolean flag = projectInfoService.updateProject(updateProject,conditionVo);
        if(!flag) {
            throw new CommonException("项目已变更，请刷新后重试");
        }
        User user = userService.getUserById(projectInfo.getUserId());
        if(Objects.isNull(user)) {
            return;
        }
        UserBill userBill = userBillService.getUserBill(user.getId(),UserBillCategoryEnum.BILL_CATEGORY2.getCategory(),2,projectInfo.getId(),projectInfo.getAireqNo());
        if(Objects.isNull(userBill)) {
            return;
        }
        if(userBill.getDataval() + userBill.getCardDataval() <= 0) {
            return;
        }
        UserDatavalVo userDatavalVo = new UserDatavalVo();
        userDatavalVo.setUserId(user.getId());
        userDatavalVo.setDataval(userBill.getDataval());
        if(userBill.getCardDataval() > 0 && user.getCardId() > 0 && user.getCardId().longValue() == userBill.getYearPid().longValue()) {
            userDatavalVo.setCardDataval(userBill.getCardDataval());
            userDatavalVo.setYearPid(userBill.getYearPid());
        }
        userDatavalVo.setPmtype(1);
        userDatavalVo.setCategoryEnum(UserBillCategoryEnum.BILL_CATEGORY5);
        userDatavalVo.setSourceType(2);
        userDatavalVo.setSourceId(projectInfo.getId());
        userDatavalVo.setSourceNo(projectInfo.getAireqNo());
        List<UserBill> userBillList = userBillService.userDataValVoToPojo(userDatavalVo);
        if(CollectionUtils.isNotEmpty(userBillList)) {
            userBillService.saveBatch(userBillList);
        }
        flag = userService.icrDataValAndCheckCardId(user.getId(),userDatavalVo.getCardDataval(),userDatavalVo.getDataval(),user.getCardId());
        if(!flag) {
            throw new CommonException("项目退款，更新用户流量包失败");
        }
    }

    @Override
    public boolean submitDelivery(Long projectId, ProjectDeliveryRequest queryRequest) {
        ProjectInfo projectInfo = new ProjectInfo();
        BeanUtils.copyProperties(queryRequest,projectInfo);
        projectInfo.setId(projectId);
        projectInfo.setDeliveryState(1);
        return projectInfoService.updateById(projectInfo);
    }

    /**
     * 编辑功能点明细保存参数检查,并组装EstimateFun对象
     * @param saveRequest
     * @param projectType
     */
    private void estimateFunSaveParamCheck(AdminEstimateFunSaveRequest saveRequest, Integer projectType) {
        if(CollectionUtils.isEmpty(saveRequest.getNewFunList())
                && CollectionUtils.isEmpty(saveRequest.getModifyFunList())
                && CollectionUtils.isEmpty(saveRequest.getDelIdList())) {
            throw new CommonException("请提交变更内容");
        }
        //新增功能明细入参检查
        AdminEstimateFunDetailSaveRequest.addParamCheck(projectType,saveRequest.getNewFunList());
        //编辑功能明细入参检查
        AdminEstimateFunDetailSaveRequest.editParamCheck(projectType,saveRequest.getModifyFunList());
    }

    private ProjectParamResponse getProjectParam(Long projectId, Integer projectType, int queryType) {
        ProjectParamResponse paramResponse = new ProjectParamResponse();
        if(Objects.isNull(projectId) || Objects.isNull(projectType)) {
            return paramResponse;
        }
        if(projectType == 1) {
            ProjectParamGuo pojo = projectParamGuoService.getParamGouByQueryType(queryType,projectId);
            if(Objects.nonNull(pojo)) {
                ProjectParamGuoResponse response = new ProjectParamGuoResponse();
                BeanUtils.copyProperties(pojo,response);
                paramResponse.setParamGuoResponse(response);
            }
        } else if(projectType == 2) {
            ProjectParamJun pojo = projectParamJunService.getParamJunByQueryType(queryType,projectId);
            if(Objects.nonNull(pojo)) {
                ProjectParamJunResponse response = new ProjectParamJunResponse();
                BeanUtils.copyProperties(pojo,response);
                paramResponse.setParamJunResponse(response);
            }
        }
        return paramResponse;
    }

    @Override
    public AiReportResponse aiReport(ReportRequest reportRequest) {
        List<PeAiWriteHistory> peAiWriteHistories = peAiWriteHistoryService.queryByTime(reportRequest.getStartDate(), reportRequest.getEndDate());
        AiReportResponse  aiReportResponse = new AiReportResponse();
        if(ObjectUtils.isNotEmpty(peAiWriteHistories)){
            aiReportResponse.setAiWriteCount(peAiWriteHistories.size());
            aiReportResponse.setAiWritePeopleCount((int) peAiWriteHistories.stream().map(PeAiWriteHistory::getUserId).distinct().count());
        }
        return aiReportResponse;
    }

    @Override
    public List<ReportDetailResponse> estimateDetail(Long projectId) {
        ProjectInfo projectInfo = projectInfoService.getById(projectId);
        Long standardId = projectInfo.getStandardId();
        //Excel树状样式
        List<ReportDetailResponse> reportDetailResponses = peStandardResultService.reportDetail(standardId);

        //查看报告使用的因子
        List<PeProjectStandard> list = peProjectStandardService.lambdaQuery().eq(PeProjectStandard::getProjectId, projectId)
                .eq(PeProjectStandard::getIsDelete, 0)
                .list();
        Map<String, String> map = new HashMap<>();
        Map<String, Object> env = new HashMap<>();
        Map<String, PeProjectStandard> standardMap = new HashMap<>();
        Set<String> significanceSet = new HashSet<>();
        significanceSet.add("重用系数");
        significanceSet.add("修改类型");
        significanceSet.add("功能点赋值");
        for (PeProjectStandard peProjectStandard : list) {
            //eg key重用系数-高 value 0.33
            String key = peProjectStandard.getName() + "-" + peProjectStandard.getKeyDescribe();
            map.put(key, peProjectStandard.getValue());
            if(!significanceSet.contains(peProjectStandard.getName())){
                String value = peProjectStandard.getValue();
                if(NumberUtil.isNumber(value)){
                    env.put(peProjectStandard.getName(), Double.valueOf(peProjectStandard.getValue()));
                }else{
                    env.put(peProjectStandard.getName(), peProjectStandard.getValue());
                }
                standardMap.put(peProjectStandard.getName(), peProjectStandard);
            }
        }


        //获取AI估算结果表
        List<EstimateFun> estimateFuns = estimateFunService.lambdaQuery().eq(EstimateFun::getProjectId, projectId).list();

        for (int i = 0; i < estimateFuns.size(); i++) {
            EstimateFun item = estimateFuns.get(i);
            //重用系数 103 低 102 中 101 高
            Integer significance = item.getItme1();
            //修改类型 101 新增 102 修改 103 删除
            Integer updateType = item.getItme2();
            // 功能点赋值
            String funType = item.getFunType();
            if(significance == 103){
                //重用系数0
                env.put("重用系数"+i, map.get("重用系数-低"));
            }else if(significance == 102){
                //重用系数0.15
                env.put("重用系数"+i, map.get("重用系数-中"));
            }else if(significance == 101){
                //重用系数0.33
                env.put("重用系数"+i, map.get("重用系数-高"));
            }
            if(updateType == 101){
                //新增
                env.put("修改类型"+i, map.get("修改类型-新增"));
            }else if(updateType == 102){
                //修改
                env.put("修改类型"+i, map.get("修改类型-修改"));
            }else if(updateType == 103){
                //删除
                env.put("修改类型"+i, map.get("修改类型-删除"));
            }

            env.put("功能点赋值"+i, map.get("功能点赋值-" + funType));
        }


        //获取标准对应的公式
        List<PeFormula> peFormulas = peFormulaService.lambdaQuery().eq(PeFormula::getStandardId, standardId)
                .eq(PeFormula::getDeleteFlag, 0)
                .orderByAsc(PeFormula::getSort).list();
        AviatorEvaluator.addFunction(new ListsumFunction());

        for (PeFormula peFormula : peFormulas) {
            String expression = peFormula.getExpression();
            log.info("expression:{}, env:{}", expression, env);
            Expression compiledExp = AviatorEvaluator.compile(expression, true);
            Double result = (Double)compiledExp.execute(env);
            BigDecimal bigDecimal = BigDecimal.valueOf(result).setScale(2, RoundingMode.HALF_UP);
            env.put(peFormula.getResult(), bigDecimal.doubleValue());
        }

        for (int i = 0; i < reportDetailResponses.size(); i++) {
            ReportDetailResponse reportDetailResponse = reportDetailResponses.get(i);
            if(ObjectUtil.isNotEmpty(reportDetailResponse.getChilds())){
                List<ReportDetailResponse> childs = reportDetailResponse.getChilds();
                for (ReportDetailResponse child : childs) {
                    setReportDetailResponsesValue(child, env, standardMap);
                }
            }else{
                setReportDetailResponsesValue(reportDetailResponse, env, standardMap);
            }
        }
        return reportDetailResponses;
    }

    public void setReportDetailResponsesValue(ReportDetailResponse reportDetailResponse, Map<String, Object> env, Map<String, PeProjectStandard> standardMap) {
        String formula = reportDetailResponse.getFormula();
        log.info("formula:{}, env:{}", formula, env);
        Expression compiledExp = AviatorEvaluator.compile(formula, true);
        Double result = (Double) compiledExp.execute(env);
        reportDetailResponse.setValue(result);
        if (ObjectUtil.isEmpty(reportDetailResponse.getParam())) {
            reportDetailResponse.setParam(standardMap.get(reportDetailResponse.getFormula()).getKeyDescribe());
        }
    }

    @Override
    public UploadResponse fileUpload(MultipartFile multipartFile) {
        if(multipartFile == null || multipartFile.isEmpty()) {
            throw new CommonException("上传文件不能为空");
        }
        String fileName = multipartFile.getOriginalFilename();
        String fileType = FilenameUtils.getExtension(fileName);
        UploadResponse uploadResponse = new UploadResponse();
        uploadResponse.setFileName(fileName);
        uploadResponse.setExtName(fileType);
        uploadResponse.setFileSize(multipartFile.getSize());
        try (InputStream in = multipartFile.getInputStream()){
            String fileUrl =  uploadService.inputStreamUpload(fileType, Constants.ORDER_DOC_PREFIX, in);
            uploadResponse.setUrl(fileUrl);
        } catch (CommonException ce) {
            throw ce;
        } catch (Exception ce) {
            throw new CommonException("文件上传失败");
        }
        return uploadResponse;
    }

    @Override
    public List<ProjectTypeStatisticsResponse> projectTypeStatistics(Long projectId) {
        List<EstimateFun> list = estimateFunService.getListByProjectId(projectId);
        if(ObjectUtil.isEmpty(list)){
            return null;
        }
        Map<String, Long> funTypeMap = list.stream().collect(Collectors.groupingBy(EstimateFun::getFunType, Collectors.counting()));
        List<ProjectTypeStatisticsResponse> responseList = new ArrayList<>();
        funTypeMap.forEach((key, value) -> {
            ProjectTypeStatisticsResponse response = new ProjectTypeStatisticsResponse();
            response.setFunType(key);
            response.setCount(value.intValue());
            responseList.add(response);
        });
        return responseList;
    }
}
